package cn.edu.sdjzu.knoverse.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.edu.sdjzu.knoverse.model.dto.kg.CaseAuditDTO;
import cn.edu.sdjzu.knoverse.model.dto.kg.CaseDetailDTO;
import cn.edu.sdjzu.knoverse.model.dto.kg.CaseQueryDTO;
import cn.edu.sdjzu.knoverse.model.entity.kg.CaseNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.ComponentNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.FileNode;
import cn.edu.sdjzu.knoverse.model.entity.kg.KnowledgeNode;
import cn.edu.sdjzu.knoverse.model.entity.system.Files;
import cn.edu.sdjzu.knoverse.model.vo.kg.FileInfoVo;
import cn.edu.sdjzu.knoverse.repository.CaseRepository;
import cn.edu.sdjzu.knoverse.service.CaseService;
import cn.edu.sdjzu.knoverse.service.ComponentService;
import cn.edu.sdjzu.knoverse.service.FilesService;
import cn.edu.sdjzu.knoverse.utils.context.BaseContext;
import cn.edu.sdjzu.knoverse.model.vo.result.ResultCodeEnum;
import cn.edu.sdjzu.knoverse.utils.exception.CustomException;
import cn.edu.sdjzu.knoverse.utils.minio.MinioUtil;
import cn.edu.sdjzu.knoverse.service.RankingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 案例节点服务实现类
 */
@Service
public class CaseServiceImpl implements CaseService {

    @Autowired
    private CaseRepository caseRepository;
    
    @Autowired
    private ComponentService componentService;
    
    @Autowired
    private RankingService rankingService;

    /**
     * 判断当前用户是否有全部案例的访问权限
     * @return 是否有权限
     */
    private boolean hasAllCasePermission() {
        return StpUtil.hasPermission("case::all");
    }

    @Override
    public Page<CaseNode> findCasesByConditions(CaseQueryDTO queryDTO) {
        // 创建分页和排序对象
        Sort sort = Sort.by(
                Sort.Direction.fromString(queryDTO.getSortDirection()),
                queryDTO.getSortBy()
        );
        Pageable pageable = PageRequest.of(queryDTO.getPage(), queryDTO.getSize(), sort);
        
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        
        // 根据用户权限查询
        if (hasAllCasePermission()) {
            // 可以查看所有案例
            return caseRepository.findByConditionsForAdmin(
                    queryDTO.getName(),
                    queryDTO.getType(),
                    queryDTO.getDifficulty(),
                    queryDTO.getStatus(),
                    pageable
            );
        } else {
            // 普通用户可以查看自己创建的所有案例（无论状态）和已发布的案例
            return caseRepository.findByConditionsForUser(
                    userId,
                    queryDTO.getName(),
                    queryDTO.getType(),
                    queryDTO.getDifficulty(),
                    queryDTO.getStatus(),
                    pageable
            );
        }
    }

    @Override
    public CaseNode findCaseById(String id) {
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        Long caseId = Long.parseLong(id);
        
        if (hasAllCasePermission()) {
            // 可以查看所有案例
            CaseNode caseNode = caseRepository.findCaseById(caseId);
            if (caseNode == null) {
                throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
            }
            return caseNode;
        } else {
            // 普通用户只能查看自己创建的和已发布的案例
            CaseNode caseNode = caseRepository.findByIdAndUserId(caseId, userId);
            if (caseNode == null) {
                throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
            }
            return caseNode;
        }
    }

    @Override
    @Transactional
    public CaseNode createCase(CaseNode caseNode) {
        // 默认设置为草稿状态
        caseNode.setStatus(0); // 0-草稿
        return caseRepository.save(caseNode);
    }

    @Override
    @Transactional
    public CaseNode updateCase(String id, CaseNode caseNode) {
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        Long caseId = Long.parseLong(id);
        
        // 检查案例是否存在
        CaseNode existingCase = caseRepository.findCaseById(caseId);
        if (existingCase == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 检查权限
        if (!hasAllCasePermission() && !existingCase.getCreatedById().equals(userId)) {
            throw new CustomException(ResultCodeEnum.NO_PERMISSION);
        }
        
        // 设置更新信息
        caseNode.setNodeId(caseId);
        return caseRepository.save(caseNode);
    }

    @Override
    @Transactional
    public void deleteCase(String id) {
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        Long caseId = Long.parseLong(id);
        
        // 检查案例是否存在
        CaseNode existingCase = caseRepository.findCaseById(caseId);
        if (existingCase == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 检查权限
        if (!hasAllCasePermission() && !existingCase.getCreatedById().equals(userId)) {
            throw new CustomException(ResultCodeEnum.NO_PERMISSION);
        }
        
        // 从排行榜中移除案例
        rankingService.removeCaseFromRanking(caseId);
        
        // 删除案例节点
        caseRepository.deleteById(caseId);
    }

    @Override
    public List<String> getAllCaseTypes() {
        return caseRepository.findAllTypes();
    }
    
    @Override
    @Transactional
    public void submitCase(String id) {
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        Long caseId = Long.parseLong(id);
        
        // 检查案例是否存在
        CaseNode existingCase = caseRepository.findCaseById(caseId);
        if (existingCase == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 检查权限（只有创建者可以提交）
        if (!existingCase.getCreatedById().equals(userId)) {
            throw new CustomException(ResultCodeEnum.NO_PERMISSION);
        }
        
        // 检查状态（只有草稿状态可以提交）
        if (existingCase.getStatus() != 0) {
            throw new CustomException(ResultCodeEnum.OPERATION_FAILED, "只有草稿状态的案例可以提交审核");
        }
        
        // 更新案例状态为审核中
        existingCase.setStatus(1); // 1-审核中
        caseRepository.save(existingCase);
    }
    
    @Override
    @Transactional
    public void publishCase(String id) {
        // 获取当前用户ID
        Long caseId = Long.parseLong(id);
        
        // 检查案例是否存在
        CaseNode existingCase = caseRepository.findCaseById(caseId);
        if (existingCase == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 更新案例状态为已发布
        existingCase.setStatus(2); // 2-已发布
        caseRepository.save(existingCase);
    }
    
    @Override
    @Transactional
    public void unpublishCase(String id) {
        // 获取当前用户ID
        Long caseId = Long.parseLong(id);
        
        // 检查案例是否存在
        CaseNode existingCase = caseRepository.findCaseById(caseId);
        if (existingCase == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 检查状态（只有已发布状态可以下架）
        if (existingCase.getStatus() != 2) {
            throw new CustomException(ResultCodeEnum.OPERATION_FAILED, "只有已发布状态的案例可以下架");
        }
        
        // 更新案例状态为已下架
        existingCase.setStatus(4); // 4-已下架
        caseRepository.save(existingCase);
    }
    
    @Override
    @Transactional
    public void auditCase(String id, CaseAuditDTO auditDTO) {
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        Long caseId = Long.parseLong(id);
        
        // 检查案例是否存在
        CaseNode existingCase = caseRepository.findCaseById(caseId);
        if (existingCase == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 检查状态（只有审核中状态可以审核）
        if (existingCase.getStatus() != 1) {
            throw new CustomException(ResultCodeEnum.OPERATION_FAILED, "只有审核中状态的案例可以进行审核");
        }
        
        // 设置审核信息
        existingCase.setAuditMessage(auditDTO.getAuditMessage());
        existingCase.setAuditor(userId);
        
        // 根据审核结果更新状态
        if (auditDTO.getPassed()) {
            existingCase.setStatus(2); // 2-已发布
        } else {
            existingCase.setStatus(3); // 3-审核未通过
        }
        caseRepository.save(existingCase);
    }
    
    @Override
    public CaseDetailDTO getCompleteCaseDetail(String id) {
        // 获取当前用户ID
        Long userId = BaseContext.getUserId();
        Long caseId = Long.parseLong(id);
        
        // 获取案例基本信息
        CaseNode caseNode;
        if (hasAllCasePermission()) {
            caseNode = caseRepository.findCaseById(caseId);
        } else {
            caseNode = caseRepository.findByIdAndUserId(caseId, userId);
        }
        
        // 检查案例是否存在
        if (caseNode == null) {
            throw new CustomException(ResultCodeEnum.CASE_NOT_FOUND);
        }
        
        // 创建返回DTO
        CaseDetailDTO detailDTO = new CaseDetailDTO();
        detailDTO.setCaseInfo(caseNode);
        
        // 获取案例的所有组件
        Set<ComponentNode> components = componentService.getComponentsByCase(caseId);
        detailDTO.setComponents(components);
        
        // 初始化组件文件和知识点映射
        Map<Long, Set<FileInfoVo>> componentFiles = new HashMap<>();
        Map<Long, Set<KnowledgeNode>> componentKnowledge = new HashMap<>();
        
        // 为每个组件获取对应的文件和知识点
        for (ComponentNode component : components) {
            Long componentId = component.getNodeId();
            
            // 获取组件的文件详细信息
            Set<FileInfoVo> fileInfoSet = componentService.getComponentFilesWithDetails(componentId);
            componentFiles.put(componentId, fileInfoSet);
            
            // 获取组件的知识点
            Set<KnowledgeNode> knowledge = componentService.getRelatedKnowledge(componentId);
            componentKnowledge.put(componentId, knowledge);
        }
        
        // 设置到返回DTO
        detailDTO.setComponentFiles(componentFiles);
        detailDTO.setComponentKnowledge(componentKnowledge);
        
        return detailDTO;
    }
} 